import cv2
import numpy as np

from .triggers.trigger import AlertTrigger
from .object_tracer import ObjectTracer
from logger import logger

class Region:

    def __init__(self, name, regions: np.ndarray=None):
        self._name = name
        self._regions = regions
        # 下面都是{类别: xx}的形式
        self._enter_triggers = {}
        self._leave_triggers = {}
        self._update_triggers = {}
        self._objects = {}

    def add_trigger(self, trigger: AlertTrigger):
        # 按照类型添加新Trigger
        for method, triggers in (
            ('enter', self._enter_triggers),
            ('leave', self._leave_triggers),
            ('update', self._update_triggers),
        ):
            if not hasattr(trigger, method):
                continue
            if trigger.object in triggers:
                triggers[trigger.object].append(trigger)
            else:
                triggers[trigger.object] = [trigger]

        # 添加物体新类别
        if trigger.object not in self._objects:
            self._objects[trigger.object] = set()
    
    def _enter(self, obj, image):
        if obj not in self._objects[obj.label]:
            # 有新物体进入该区域
            logger.debug(f'({obj.id})物体[{obj.label}]进入区域[{self._name}]')
            self._objects[obj.label].add(obj)
            if obj.label in self._enter_triggers:
                for trigger in self._enter_triggers[obj.label]:
                    trigger.enter(obj, self._objects[obj.label], image)
    
    def _leave(self, obj, image):
        if obj in self._objects[obj.label]:
            # 有物体离开该区域
            logger.debug(f'({obj.id})物体[{obj.label}]离开区域[{self._name}]')
            self._objects[obj.label].discard(obj)
            if obj.label in self._leave_triggers:
                for trigger in self._leave_triggers[obj.label]:
                    trigger.leave(obj, self._objects[obj.label], image)

    def update_object(self, obj: ObjectTracer, image, leave=False):
        if obj.label not in self._objects:
            return
        
        # 物体都离开画面了（物体如果进入画面不用额外判断，因为物体会在物体列表里，走下面的判断）
        if leave:
            self._leave(obj, image)
            return

        # 当该区域是全图区域或者该物体在该区域时
        if self._regions is None or cv2.pointPolygonTest(self._regions, obj.get_pos(), False) == 1:
            self._enter(obj, image)
        else:
            self._leave(obj, image)

    def update(self, image):
        for label, triggers in self._update_triggers.items():
            for trigger in triggers:
                trigger.update(self._exist_objs[label], image)
    
    # 当无trigger时，该区域为空区域
    def empty(self):
        return len(self._objects) == 0